<?php
/**
 * 后台店铺Store的管理
 * Author: lyun
 * Date: 2018/4/2
 * Created by Panxsoft.
 */


namespace App\Http\Controllers\Admin\Store;

use App\Http\Controllers\ApiController;
use App\Http\Requests\Admin\Store\StaffBindQrCodeRequest;
use App\Http\Requests\Admin\Store\StaffIndexRequest;
use App\Http\Requests\Admin\Store\StaffOperateRequest;
use App\Http\Requests\Admin\Store\StaffStoreRequest;
use App\Http\Requests\Admin\Store\StaffUpdateRequest;
use App\Models\Admin\StoreAdmin;
use App\Models\OpenWechat\ScanEvent;
use App\Services\Locale\Language;
use App\Services\OpenWechat\Contracts\EventMessageHandler;
use App\Services\OpenWechat\QrCode;
use App\Services\OpenWechat\ScanEventHandler;
use App\Services\Utils\Guard;
use App\Services\Utils\SimpleQrCode;
use App\Services\Utils\Transaction;
use Carbon\Carbon;
use Illuminate\Http\Request;
use App\Models\Admin\Role;

class StoreStaffController extends ApiController
{
    const ROUTES = [
        'index'  => 'api.admin.store.staff.index',
        'store'  => 'api.admin.store.staff.store',
        'update' => 'api.admin.store.staff.update',
        'patch'  => 'api.admin.store.staff.patch',
        'bind'   => 'api.admin.store.staff.bind',
        'unbind' => 'api.admin.store.staff.unbind',
    ];

    /**
     * Display a listing of the resource.
     * @test
     *
     * @param StaffIndexRequest $request
     * @return \Illuminate\Http\Response
     * @throws \Exception
     */
    public function index(StaffIndexRequest $request)
    {
        $this->checkIsTrue(StoreAdmin::checkIsSuperMan(), trans('admin.is_super_man'));

        // 显示所有，除了自己
        $customer_admin = StoreAdmin::filterIsSuperMan()
            ->columnsKeywordsOrLike([
                'name'    => $request->keyword,
                'account' => $request->keyword,
                'email'   => $request->keyword,
                'phone'   => $request->keyword,
            ])
            ->where('store_id', Guard::store()->id)
            ->with('roles', 'wechatUser')
            ->orderBy($request->order_by ?? 'created_at', $request->sort ?? 'desc')
            ->paginate($request->per_page ?: 15);

        return $this->response(compact('customer_admin'));
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        $roles = Role::where('guard_name', StoreAdmin::GUARD_NAME)
            ->where('is_deleted', Role::ROLE_IS_NOT_DELETED)
            ->get(['id', Language::getLocalNameColumn()]);

        return $this->response(compact('roles'));
    }

    /**
     * Store a newly created resource in storage.
     * @test
     *
     * @param  StaffStoreRequest $request
     * @return \Illuminate\Http\Response
     * @throws \Exception
     */
    public function store(StaffStoreRequest $request)
    {
        // 超管才能操作的
        $this->checkIsTrue(StoreAdmin::checkIsSuperMan(), trans('admin.is_super_man'));

        $store_admin = $this->assembleStaffStoreData($request);
        $role_name = $this->getChineseRole($request->role_name);

        $stored = Transaction::handle(function () use ($role_name, $store_admin) {

            /** @var StoreAdmin $admin */
            $admin = StoreAdmin::create($store_admin);

            $admin->assignRole($role_name);

            return $admin;
        });

        return $this->response(compact('stored'));
    }

    /**
     * 更新自己 和 超管更新职员的信息
     * @test
     *
     * @param  StaffUpdateRequest $request
     * @param  int $id
     * @return \Illuminate\Http\Response
     * @throws \Exception
     */
    public function update(StaffUpdateRequest $request, $id)
    {
        /** @var StoreAdmin $store_admin */
        $store_admin = StoreAdmin::where('store_id', Guard::store()->id)
            ->find($id);
        $this->checkItemExist($store_admin, trans('admin.store_admin'));

        $store_admin_data = $this->assembleStaffStoreData($request);

        $is_super_man = StoreAdmin::checkIsSuperMan();
        $is_update_self = (Guard::storeAdmin()->id === (int)$id);

        if ($is_update_self) { // 更新自己

            $updated = $store_admin->update($store_admin_data);
        } else if ($is_super_man) { // 超管更新职员

            $updated = $this->updateStoreStaff($store_admin, $store_admin_data, $request->role_name);
        } else {

            $this->checkIsTrue(false, trans('admin.illegality_store_admin'));
        }

        $store_admin = $store_admin->load('Roles');

        return $this->response(compact('updated', 'store_admin'));
    }

    /**
     * @deprecated (废弃，改成启用和禁用了！)
     *
     * Remove the specified resource from storage.
     *
     * @param  int $id
     * @return \Illuminate\Http\Response
     * @throws \Exception
     */
    public function destroy($id)
    {
        $this->checkIsTrue($id !== Guard::storeAdmin()->id, '管理员不能删除自己');
        $this->checkIsTrue(Guard::storeAdmin()->isSuperMan(), '只有管理员能删除员工');

        /** @var StoreAdmin $staff */
        $staff = StoreAdmin::where('store_id', Guard::storeAdmin()->store_id)
            ->find($id);
        $this->checkIsTrue($staff, '错误的管理员ID');

        $deleted = $staff->delete();

        return $this->response(compact('deleted'));
    }

    /**
     * 启用和禁用后台管理员
     * @test
     *
     * @param StaffOperateRequest $request
     * @param $staff_id
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function patchEnabled(StaffOperateRequest $request, $staff_id)
    {
        // 超管才能操作的
        $this->checkIsTrue(StoreAdmin::checkIsSuperMan(), trans('admin.is_super_man'));

        // 不能禁用第一个超管
        $first_store_admin = StoreAdmin::where('store_id', Guard::store()->id)
            ->oldest()
            ->first();
        $this->checkUnless($first_store_admin->id === (int)$staff_id, trans('admin.first_store_admin'));

        /** @var StoreAdmin $store_admin */
        $store_admin = StoreAdmin::where('store_id', Guard::store()->id)
            ->find($staff_id);
        $this->checkItemExist($store_admin, trans('admin.store_admin'));

        $updated = $store_admin->update([
            'is_deleted'     => $request->is_deleted,
            'wechat_user_id' => 0
        ]);

        return $this->response(compact('updated', 'store_admin'));
    }

    /**
     * @param StaffStoreRequest|StaffUpdateRequest|Request $request
     * @return array
     */
    private function assembleStaffStoreData(Request $request)
    {
        return [
            'store_id' => Guard::store()->id,
            'name'     => $request->name,
            'email'    => $request->email,
            'account'  => $request->account,
            'password' => $request->password,
            'phone'    => $request->phone,
            'sex'      => $request->sex,
            'born_at'  => $request->born_at ?? Carbon::now(),
        ];
    }

    /**
     * 绑定微信二维码 (重复绑定，会覆盖之前微信绑定, 一个微信只能绑定一个店员)
     * @test
     *
     * @see ScanEventHandler::handleStoreAdminBind - 扫码处理方法
     *
     * @param StaffBindQrCodeRequest $request
     * @param $store_admin_id
     * @return array|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response|\Symfony\Component\HttpFoundation\Response
     * @throws \Exception
     */
    public function bindQrCode(StaffBindQrCodeRequest $request, $store_admin_id)
    {
        $admin = StoreAdmin::where('is_deleted', StoreAdmin::IS_NOT_DELETED)
            ->find($store_admin_id);
        $this->checkIsTrue($admin, trans('admin.no_admin_or_deleted'));

        $this->checkCanOperate(
            $admin->store_id === Guard::store()->id,
            trans('admin.store_has_store_admin')
        );

        $authorizer = Guard::store()->getAuthorizer();
        $this->checkItemExist($authorizer, trans('admin.authorizer'));

        $scan_event = ScanEvent::createNewEvent(
            ScanEvent::TYPE_STORE_STAFF_BIND,
            $admin->id
        );

        $qr_result = QrCode::generate(
            $authorizer->authorizer_appid,
            $scan_event->getSceneValue()
        );
        if (! isset($qr_result['url'])) {
            $this->checkFailed($qr_result['errmsg']);
        }

        $url = $qr_result['url'];
        if ($request->type === 'png') {
            return $this->responseImage(SimpleQrCode::toImage($url));
        }

        $code_img_url = QrCode::ticketToQrCodeUrl($authorizer->authorizer_appid, $qr_result['ticket']);
        $scan_event_id = $scan_event->id;

        return $this->response(compact('url', 'scan_event_id', 'code_img_url'));
    }

    /**
     * 解除微信店员绑定
     * @test
     *
     * @param $store_admin_id
     * @return \Illuminate\Http\Response
     * @throws \Exception
     */
    public function patchUnbindWechat($store_admin_id)
    {
        // 超管才能操作的
        $this->checkIsTrue(StoreAdmin::checkIsSuperMan(), trans('admin.is_super_man'));

        /** @var StoreAdmin $admin */
        $admin = StoreAdmin::find($store_admin_id);
        $this->checkItemExist($admin, trans('admin.store_admin'));
        $this->checkCanOperate(
            $admin->store_id === Guard::store()->id,
            trans('admin.store_has_store_admin')
        );

        $updated = $admin->update(['wechat_user_id' => 0]);

        return $this->response(compact('updated'));
    }

    /**
     * @param $role_name
     * @return null
     * @throws \Exception
     */
    private function getChineseRole($role_name)
    {
        $language = app()->getLocale();

        if ($language === 'en') {
            $role_name = isset(StoreAdmin::ROLE_RELATION[$role_name])
                ? StoreAdmin::ROLE_RELATION[$role_name]
                : null;
            $this->checkIsTrue($role_name, trans('admin.role_name'));
        }

        return $role_name;
    }

    /**
     * @param StoreAdmin $store_admin
     * @param array $store_admin_data
     * @param $role_name
     * @return mixed
     * @throws \Exception
     */
    private function updateStoreStaff(StoreAdmin $store_admin, array $store_admin_data, $role_name)
    {
        $updated = Transaction::handle(function () use ($store_admin, $store_admin_data, $role_name) {

            $this->editStaffRole($store_admin, $role_name);

            $updated = $store_admin->update($store_admin_data);

            return $updated;
        });

        return $updated;
    }

    /**
     * @param StoreAdmin $store_admin
     * @param $role_name
     * @return bool
     * @throws \Exception
     */
    private function editStaffRole(StoreAdmin $store_admin, $role_name)
    {
        if (!$role_name) return true;
        $role_name = $this->getChineseRole($role_name);

        //不能修改第一个超管的角色
        $first_store_admin = StoreAdmin::where('store_id', Guard::store()->id)
            ->oldest()
            ->first();

        $admin_is_oldest = $first_store_admin->id === $store_admin->id;
        $admin_had_role = $store_admin->hasRole($role_name);

        if ($admin_is_oldest) {
            $this->checkIsTrue($admin_had_role, trans('admin.edit_first_store_admin'));

            return true;
        }

        $store_admin->syncRoles($role_name);

        return true;
    }
}
